<script setup lang="ts">
import { computed, onBeforeUnmount, reactive, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { JBoltApi } from '@/utils/request'
import { UploadTo } from '@/typings/common'
import { getServiceEnvConfig } from '~/.env-config'

const props = withDefaults(
    defineProps<{
        modelValue: string
        placeholder?: string
        editorConfig?: Record<string, any>
        toolbarConfig?: Record<string, any>
        excludeKeys?: string[]
        /** 上传到哪里，暂时只支持七牛上传 */
        uploadTo?: UploadTo
        /** 上传到哪个七牛账号，不传则使用默认七牛账号，但后台需要配置 */
        qiniuSn?: string
        /** 视频保存路径 */
        videoSavePath?: string
        /** 图片保存路径 */
        imgSavePath?: string
    }>(),
    {
        modelValue: '',
        placeholder: '请输入内容...',
        excludeKeys: () => ['sub', 'sup', 'bgColor', 'delIndent', 'enter'],
        videoSavePath: 'video/editor/{date(yyMMddHHmm)}/{random(5)}/{ori}',
        imgSavePath: 'img/editor/{date(yyMMddHHmm)}/{random(5)}/{ori}'
    }
)

const emit = defineEmits<{
    'update:modelValue': [value: string]
}>()

const uploadTo = computed(() => {
    const { defaultUploadTo } = getServiceEnvConfig(import.meta.env)
    return props.uploadTo || defaultUploadTo
})
const qiniuSn = computed(() => {
    const { defaultQiniuSn } = getServiceEnvConfig(import.meta.env)
    return props.qiniuSn || defaultQiniuSn
})

watch(
    () => props.modelValue,
    () => {
        if (state.html == props.modelValue) return
        state.html = props.modelValue
    }
)

const editorRef = shallowRef()

const state = reactive({
    editor: null,
    html: '',
    mode: 'default' // or 'simple'
})

watch(
    () => state.html,
    () => {
        emit('update:modelValue', state.html)
    }
)

type InsertImgFnType = (url: string, alt: string, href: string) => void
function handleImgUpload(file: File, insertFn: InsertImgFnType) {
    switch (uploadTo.value) {
        case 'qiniu':
            JBoltApi.uploadToQiniu(file, props.imgSavePath, qiniuSn.value).then((url) => {
                insertFn(url as string, '', url as string)
            })
            break
        case 'server':
            JBoltApi.uploadToServer(file, props.imgSavePath).then((url) => {
                insertFn(url as string, '', url as string)
            })
            break
        default:
            throw new Error('不支持的上传类型')
    }
}
type InsertVideoFnType = (url: string, poster: string) => void
function handleVideoUpload(file: File, insertFn: InsertVideoFnType) {
    switch (uploadTo.value) {
        case 'qiniu':
            JBoltApi.uploadToQiniu(file, props.videoSavePath, props.qiniuSn).then(
                (url) => {
                    insertFn(url as string, '')
                }
            )
            break
        case 'server':
            JBoltApi.uploadToServer(file, props.videoSavePath).then((url) => {
                insertFn(url as string, '')
            })
            break
        default:
            throw new Error('不支持的上传类型')
    }
}

const editorConfig = computed(() => {
    var config = Object.assign({}, { placeholder: props.placeholder }, props.editorConfig)
    if (!config.MENU_CONF) {
        config.MENU_CONF = {}
    }
    if (!config.MENU_CONF['uploadImage']) {
        config.MENU_CONF['uploadImage'] = {
            customUpload: handleImgUpload
        }
    }
    if (!config.MENU_CONF['uploadVideo']) {
        config.MENU_CONF['uploadVideo'] = {
            customUpload: handleVideoUpload
        }
    }
    return config
})

const toolbarConfig = computed(() => {
    return Object.assign(
        {},
        {
            excludeKeys: props.excludeKeys
        },
        props.toolbarConfig
    )
})

function onCreated(editor: any) {
    editorRef.value = editor
    if (props.modelValue) {
        state.html = props.modelValue
    }
}

onBeforeUnmount(() => {
    const editor = editorRef.value
    if (editor == null) return
    editor.destroy() // 组件销毁时，及时销毁编辑器
})
</script>

<template>
    <div class="flex-col" style="border: 1px solid #ccc">
        <Toolbar
            style="border-bottom: 1px solid #ccc"
            class="shrink-0"
            :editor="editorRef"
            :default-config="toolbarConfig"
            :mode="state.mode"
        />
        <Editor
            v-model="state.html"
            style="flex:1;overflow: hidden"
            :default-config="editorConfig"
            :mode="state.mode"
            @onCreated="onCreated"
        />
    </div>
</template>

<style scoped></style>
